#ifndef THREADPOOL_H
#define THREADPOOL_H

#include "Mutex.h"
#include "Thread.h"
#include <type_traits>
#include <functional>

template<class T>
class CThreadPool
{
private:
    CThreadPool();
    typename std::enable_if<std::is_base_of<Thread, T>::value>::type Init(
        int threadnum, eRole role, int roleID, SyncQueue<string>* queue, std::function<void(eAckInfo, uint64_t, DataContainerPtr)> func
    );

    static CThreadPool* m_pInstance;
    static CMutexLock m_Mutex;
    class CGarbo
    {
    public:
        ~CGarbo()
        {
            if(m_pInstance)
                delete m_pInstance;
        }
    };
    static CGarbo Garbo;
    vector<T*> m_ThreadPool;

public:
    ~CThreadPool();
    static CThreadPool* GetInstance();
    void StartThread(
        int threadnum, eRole role, int roleID, SyncQueue<string>* queue, std::function<void(eAckInfo, uint64_t, DataContainerPtr)> func
    );

    void StopThread();
};

template<class T>
CThreadPool<T>* CThreadPool<T>::m_pInstance = nullptr;
template<class T>
CMutexLock CThreadPool<T>::m_Mutex;

template<class T>
CThreadPool<T>::CThreadPool()
{
}

template<class T>
typename std::enable_if<std::is_base_of<Thread, T>::value>::type
CThreadPool<T>::Init(
    int threadnum, eRole role, int roleID, SyncQueue<string>* queue, std::function<void(eAckInfo, uint64_t, DataContainerPtr)> func
)
{
    int i = 0;
    for (; i < threadnum; i++)
    {
        T* pThread = new T(role, roleID, queue, func);
        assert(pThread != nullptr);
        m_ThreadPool.push_back(pThread);
    }
}

template<class T>
CThreadPool<T>::~CThreadPool()
{
    for (auto it = m_ThreadPool.begin(); it != m_ThreadPool.end();  ++it)
    {
        if ((*it) != nullptr)
        {
            delete (*it);
        (*it) = nullptr;
        }
    }
    m_ThreadPool.clear();
}

template<class T>
CThreadPool<T>* CThreadPool<T>::GetInstance()
{
    if(m_pInstance == NULL)
    {
        //double check
        CSynchronizeAccess lock(m_Mutex);
        if(m_pInstance == NULL)
        {
            m_pInstance = new CThreadPool<T>();
        }
    }
    return m_pInstance;
}

template<class T>
void CThreadPool<T>::StartThread(
    int threadnum, eRole role, int roleID, SyncQueue<string>* queue, std::function<void(eAckInfo, uint64_t, DataContainerPtr)> func
)
{
    CThreadPool<T>::Init(threadnum, role, roleID, queue, func);
    for (auto it = m_ThreadPool.begin(); it != m_ThreadPool.end();  ++it)
    {
        if ((*it) != nullptr)
        {
            (*it)->StartThread();
        }
    }
}

template<class T>
void CThreadPool<T>::StopThread()
{
    for (auto it = m_ThreadPool.begin(); it != m_ThreadPool.end();  ++it)
    {
        if ((*it) != nullptr)
        {
            (*it)->StopThread();
        }
    }
}


#endif // SERVICETHREADPOOL_H
